package cn.edu.zafu.bigdata.YinMingyan.chapter10;

public class SynchronizedDemo2 {
    public static void main(String[] args) throws Exception{
        //使用var关键字创建Thread类型数组，编译器可自动推断数组的类型
        var ts = new Thread[]{
             new AddStudentThread(),
             new DecStudentThread(),
             new AddTeacherThread(),
             new DecTeacherThread()
        };
        //启动数组中的线程
        for(var t:ts){ //var 关键字用于声明循环变量 t，编译器会根据数组 ts 中的元素类型（这里是 Thread 类型的对象）来推断 t 的类型。
            t.start();
        }
        for(var t:ts){
            t.join();
        }
        System.out.println(Counter2.studentCount);
        System.out.println(Counter2.teacherCount);
    }
}

class Counter2 {
    //public static final Object lock = new Object();
    public static final Object lockStudent = new Object();
    public static final Object lockTeacher = new Object();

    public static int studentCount = 0;
    public static int teacherCount = 0;
}

class AddStudentThread extends Thread {
    public void run() {
        for (int i=0; i<10000; i++) {
            //使用的锁都是Counter2.lock这一个对象
//            synchronized(Counter2.lock) {
//                Counter2.studentCount += 1;
//            }
            //使用的锁是Counter2.lockStudent这一个对象
            synchronized(Counter2.lockStudent) {
                Counter2.studentCount += 1;
            }
        }
    }
}

class DecStudentThread extends Thread {
    public void run() {
        for (int i=0; i<10000; i++) {
            //使用的锁都是Counter2.lock这一个对象
//            synchronized(Counter2.lock) {
//                Counter2.studentCount -= 1;
//            }
            //使用的锁是Counter2.lockStudent这一个对象
            synchronized(Counter2.lockStudent) {
                Counter2.studentCount -= 1;
            }
        }
    }
}

class AddTeacherThread extends Thread {
    public void run() {
        for (int i=0; i<10000; i++) {
            //使用的锁都是Counter2.lock这一个对象
//            synchronized(Counter2.lock) {
//                Counter2.teacherCount += 1;
//            }
            ////使用的锁是Counter2.lockTeacher这一个对象
            synchronized(Counter2.lockTeacher) {
                Counter2.teacherCount += 1;
            }
        }
    }
}

class DecTeacherThread extends Thread {
    public void run() {
        for (int i=0; i<10000; i++) {
            //使用的锁都是Counter2.lock这一个对象
//            synchronized(Counter2.lock) {
//                Counter2.teacherCount -= 1;
//            }
            //使用的锁是Counter2.lockTeacher这一个对象
            synchronized(Counter2.lockTeacher) {
                Counter2.teacherCount -= 1;
            }
        }
    }
}

/*
上述代码(注释掉的部分)中的4个线程对两个共享变量分别进行读写操作，但是使用的锁都是Counter2.lock这一个对象，
这就造成了原本可以并发执行的Counter2.studentCount += 1和Counter2.teacherCount += 1，现在无法并发执行了，执行效率大大降低。
实际上，需要同步的线程可以分成两组：AddStudentThread和DecStudentThread，AddTeacherThread和DecTeacherThread，组之间不存在竞争，
因此，应该使用两个不同的锁，即：AddStudentThread和DecStudentThread使用lockStudent锁：
synchronized(Counter2.lockStudent) {
    ...
}

synchronized(Counter2.lockTeacher) {
    ...
}
 */
